package com.dycx.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dycx.common.Common;
import com.dycx.common.RestResponse;
import com.dycx.message.dto.VerificationCodeDTO;
import com.dycx.message.service.VerificationCodeService;
import com.dycx.payment.entity.PaymentOrderDO;
import com.dycx.system.service.RegionService;
import com.dycx.system.service.OssFileService;
import com.dycx.user.constants.UserConstants;
import com.dycx.user.converter.UserConverter;
import com.dycx.user.dto.UserDTO;
import com.dycx.user.entity.UserDO;
import com.dycx.user.entity.UserInfoDO;
import com.dycx.user.entity.WalletLogDO;
import com.dycx.user.enums.AgencyGradeEnum;
import com.dycx.user.enums.SetMealEnum;
import com.dycx.user.enums.TransactionTypeEnum;
import com.dycx.user.enums.VipTypeEnum;
import com.dycx.user.mapper.UserMapper;
import com.dycx.user.mapper.WalletLogMapper;
import com.dycx.user.service.UserInfoService;
import com.dycx.user.service.UserService;
import com.dycx.user.service.WalletLogService;
import com.dycx.user.vo.UserInfoVO;
import com.dycx.user.vo.UserVO;
import lombok.AllArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
@AllArgsConstructor
public class UserImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    private UserInfoService userInfoService;
    private OssFileService ossFileService;
    private RegionService regionService;
    private VerificationCodeService verificationCodeService;
    private WalletLogService walletLogService;
    private WalletLogMapper walletLogMapper;

    /**
     * 删除管理员
     *
     * @param uid
     * @return
     */
    @Override
    public Boolean delete(int uid) {
        UserInfoVO oldEntity = userInfoService.load(uid);

        if (!this.removeById(uid)) return false;
        if (!userInfoService.removeById(uid)) return false;

        ossFileService.setDeleted(oldEntity.getAvatar());
        return true;
    }

    /**
     * 重置密码
     *
     * @param uid
     * @return
     */
    @Override
    public String restPassword(int uid) {
        String password = Common.createRandom(8, 1);

        UserDO userDO = new UserDO();
        userDO.setUid(uid);
        userDO.setPassword(DigestUtils.md5Hex(password + UserConstants.PASSWORD_SALT));
        if (!this.updateById(userDO)) {
            throw new RuntimeException("密码重置失败");
        }

        return password;
    }

    /**
     * 添加
     *
     * @param userDto
     * @return
     */
    @Override
    public String insert(UserDTO userDto) {
        if (userDto.getUsername() != null) {
            LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserDO::getUsername, userDto.getUsername());

            if (this.getOne(queryWrapper) != null) {
                throw new RuntimeException("登录名已存在，请勿重复添加");
            }
        }

        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getMobile, userDto.getMobile());

        if (this.getOne(queryWrapper) != null) {
            throw new RuntimeException("手机号已存在，请勿重复添加");
        }

        String password = Common.createRandom(8, 1);
        UserDO user = BeanUtil.toBean(userDto, UserDO.class);
        user.setPassword(DigestUtils.md5Hex(password + UserConstants.PASSWORD_SALT));
        user.setCreateTime(LocalDateTime.now());
        if (!this.save(user)) {
            throw new RuntimeException("添加用户失败");
        }

        UserInfoDO userInfoDO = regionService.replenish(BeanUtil.toBean(userDto, UserInfoDO.class));
        userInfoDO.setUid(user.getUid());

        //设置默认昵称
        if (userInfoDO.getNickname() == null) {
            if (user.getUsername() != null) {
                userInfoDO.setNickname(user.getUsername());
            } else if (user.getMobile() != null) {
                userInfoDO.setNickname(user.getMobile());
            }
        }

        if (!userInfoService.save(userInfoDO)) {
            throw new RuntimeException("添加用户信息失败");
        }

        ossFileService.setUse(userDto.getAvatar());
        userDto.setUid(user.getUid());

        return password;
    }

    /**
     * 修改
     *
     * @param userDto
     * @return
     */
    @Override
    public Boolean update(UserDTO userDto) {
        UserInfoVO oldEntity = userInfoService.load(userDto.getUid());

        UserInfoDO userInfo = regionService.replenish(BeanUtil.toBean(userDto, UserInfoDO.class));

        if (!userInfoService.edit(userInfo)) {
            throw new RuntimeException("修改用户信息失败");
        }

        ossFileService.setDeleted(oldEntity.getAvatar());
        ossFileService.setUse(userInfo.getAvatar());

        return true;
    }

    /**
     * 更新状态
     *
     * @param userDto
     * @return
     */
    @Override
    public Boolean updateStatus(UserDTO userDto) {
        UserDO user = new UserDO();
        user.setUid(userDto.getUid());
        user.setStatus(userDto.getStatus());
        return this.updateById(user);
    }

    @Override
    public UserVO load(Integer uid) {
        UserVO userVO = UserConverter.entityToVo(getById(uid));
        BeanUtil.copyProperties(userInfoService.load(uid), userVO);

        return userVO;
    }


    @Override
    public Page<UserVO> getPage(UserDTO dto) {
        LambdaQueryWrapper<UserDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getUsername()), UserDO::getUsername, dto.getUsername());
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getMobile()), UserDO::getMobile, dto.getMobile());
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getRealName()), UserDO::getRealName, dto.getRealName());
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getIdCard()), UserDO::getIdCard, dto.getIdCard());
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getUid()), UserDO::getUid, dto.getUid());
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getShareUid()), UserDO::getShareUid, dto.getShareUid());
        if ("team".equals(dto.getQueryType())) {
            wrapper.and(o -> {
                o.gt(UserDO::getVipGrade, 0)
                        .or()
                        .gt(UserDO::getAgencyGrade, 0);
            });
        }
        if ("agency".equals(dto.getQueryType())) {
            wrapper.gt(UserDO::getAgencyGrade, 0);
        }
        wrapper.orderByDesc(UserDO::getUid);

        Page<UserDO> entityPage = page(new Page<>(dto.getPageIndex(), dto.getPageSize()), wrapper);
        Page<UserVO> voPage = UserConverter.entityToVoPage(entityPage);
        voPage.setRecords(setListData(voPage.getRecords(), dto));

        return voPage;
    }

    /**
     * 设置数据
     *
     * @param userList 实体
     * @return 查询结果
     */
    public List<UserVO> setListData(List<UserVO> userList, UserDTO dto) {
        if (ObjectUtil.isEmpty(userList)) {
            return userList;
        }

        List<Integer> uids = userList.stream()
                .map(UserVO::getUid)
                .collect(Collectors.toList());

        List<UserInfoVO> userInfoList = userInfoService.getList(uids);

        userList.forEach(item -> {
            List<UserInfoVO> userInfoVOList = userInfoList.stream()
                    .filter(o -> o.getUid().equals(item.getUid()))
                    .collect(Collectors.toList());
            BeanUtil.copyProperties(userInfoVOList.get(0), item);
        });

        return userList;
    }

    @Override
    public UserVO getInfoByUsername(String username) {
        LambdaQueryWrapper<UserDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDO::getUsername, username).or().eq(UserDO::getMobile, username);

        UserVO userVO = UserConverter.entityToVo(getOne(wrapper));
        BeanUtil.copyProperties(userInfoService.load(userVO.getUid()), userVO);

        return userVO;
    }

    /**
     * 用户修改密码
     *
     * @param dto
     * @param
     * @return
     */
    @Override
    public Boolean updatePassword(UserDTO dto) {
        UserDO userDO = new UserDO();
        userDO.setUid(dto.getUid());
        userDO.setPassword(DigestUtils.md5Hex(dto.getPassword() + UserConstants.PASSWORD_SALT));

        return updateById(userDO);
    }

    /**
     * 修改手机号
     *
     * @param dto
     * @param
     * @return
     */
    @Override
    public Boolean updateMobile(UserDTO dto) {
        VerificationCodeDTO verificationCodeDTO = new VerificationCodeDTO();
        verificationCodeDTO.setMobile(dto.getMobile());
        verificationCodeDTO.setCode(dto.getCode());
        verificationCodeService.checkVerificationCode(verificationCodeDTO);

        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getMobile, dto.getMobile());

        if (ObjectUtil.isNotEmpty(getOne(queryWrapper))) {
            throw new RuntimeException("手机号已存在，请更换手机号");
        }

        UserDO userDO = new UserDO();
        userDO.setUid(dto.getUid());
        userDO.setMobile(dto.getMobile());

        return updateById(userDO);
    }

    @Override
    @Transactional
    public RestResponse<T> payNotify(PaymentOrderDO paymentOrderDO) {

        //处理支付用户信息
        UserVO payUserVO = this.load(paymentOrderDO.getUid());

        SetMealEnum setMealEnum = SetMealEnum.getItem(Convert.toInt(paymentOrderDO.getBizOrderNo()));

        UserDO userDO = new UserDO();
        userDO.setUid(payUserVO.getUid());
        userDO.setVipGrade(setMealEnum.getVip());
        if (setMealEnum.getMonth() == -1) {
            userDO.setVipType(VipTypeEnum.PERPETUAL.getCode());
        } else {
            userDO.setVipType(VipTypeEnum.LIMITED.getCode());
        }
        if (ObjectUtil.isNotEmpty(payUserVO.getVipExpiredTime())) {
            userDO.setVipExpiredTime(payUserVO.getVipExpiredTime().plusMonths(setMealEnum.getMonth()));
        } else {
            userDO.setVipExpiredTime(LocalDateTime.now().plusMonths(setMealEnum.getMonth()));
        }
        if (SetMealEnum.PERPETUAL.getCode().equals(setMealEnum.getCode())) {
            userDO.setAgencyGrade(AgencyGradeEnum.GOLD.getCode());
        }

        updateById(userDO);

        WalletLogDO walletLogDO = new WalletLogDO();
        walletLogDO.setUid(payUserVO.getUid());
        walletLogDO.setTransactionType(TransactionTypeEnum.RECHARGE_AMOUNT.getCode());
        walletLogDO.setTitle("在线充值");
        walletLogDO.setAmount(paymentOrderDO.getAmount());
        walletLogDO.setAccountBalance(payUserVO.getAccountBalance() + paymentOrderDO.getAmount());
        walletLogDO.setOutTradeNo(paymentOrderDO.getOutTradeNo());
        walletLogService.save(walletLogDO);

        walletLogDO.setTransactionType(TransactionTypeEnum.PAY_VIP.getCode());
        walletLogDO.setTitle("购买会员");
        walletLogDO.setAmount(-paymentOrderDO.getAmount());
        walletLogDO.setAccountBalance(payUserVO.getAccountBalance());
        walletLogService.save(walletLogDO);

        if (ObjectUtil.isEmpty(payUserVO.getShareUid())) return RestResponse.success();

        //分销处理
        UserVO parentUserVO = load(payUserVO.getShareUid());
        if (ObjectUtil.isEmpty(parentUserVO)) return RestResponse.success();

        //获取收益
        if (parentUserVO.getAgencyGrade() > 0) {
            //获取收益
            Integer rate = AgencyGradeEnum.converter(parentUserVO.getAgencyGrade()).getRate();
            Integer shareMoney = paymentOrderDO.getAmount() * rate / 100;

            UserInfoDO parentUserInfo = new UserInfoDO();
            parentUserInfo.setUid(parentUserVO.getUid());
            parentUserInfo.setAccountBalance(parentUserVO.getAccountBalance() + shareMoney);
            userInfoService.edit(parentUserInfo);

            WalletLogDO parentWalletLogDO = new WalletLogDO();
            parentWalletLogDO.setUid(parentUserVO.getUid());
            parentWalletLogDO.setTransactionType(TransactionTypeEnum.DISTRIBUTION_INCOME.getCode());
            parentWalletLogDO.setTitle("推广收益");
            parentWalletLogDO.setAmount(shareMoney);
            parentWalletLogDO.setAccountBalance(parentUserVO.getAccountBalance() + shareMoney);
            parentWalletLogDO.setOutTradeNo(paymentOrderDO.getOutTradeNo());
            walletLogService.save(parentWalletLogDO);
        }

        //统计分销人数，自动升级代理
        if (!parentUserVO.getAgencyGrade().equals(AgencyGradeEnum.DIAMOND.getCode())) {
            Integer agencyGrade = 0;

            LambdaQueryWrapper<UserDO> countWrapper = new LambdaQueryWrapper<>();
            countWrapper.eq(UserDO::getShareUid, payUserVO.getShareUid());
            countWrapper.gt(UserDO::getVipType, 0);
            if (count(countWrapper) >= 10) {
                agencyGrade = AgencyGradeEnum.DIAMOND.getCode();
            } else if (count(countWrapper) >= 5) {
                agencyGrade = AgencyGradeEnum.GOLD.getCode();
            }
            if (agencyGrade > 0) {
                UserDO shareUserDO = new UserDO();
                shareUserDO.setUid(parentUserVO.getUid());
                shareUserDO.setAgencyGrade(agencyGrade);
                updateById(shareUserDO);
            }
        }

        return RestResponse.success();
    }

    /**
     * 统计数据
     *
     * @param uid
     * @return
     */
    @Override
    public Map<String, Integer> statisticsTeamData(Integer uid) {
        Map<String, Integer> map = new HashMap<>();

        //邀请人数
        LambdaQueryWrapper<UserDO> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(UserDO::getShareUid, uid);
        map.put("inviteNum", count(userWrapper));

        //推广用户vip人数
        LambdaQueryWrapper<UserDO> userWrapper2 = new LambdaQueryWrapper<>();
        userWrapper2.eq(UserDO::getShareUid, uid);
        userWrapper2.gt(UserDO::getVipGrade, 0);
        List<UserDO> userList = list(userWrapper2);
        map.put("vipNum", userList.size());

        //代理人数
        LambdaQueryWrapper<UserDO> userWrapper3 = new LambdaQueryWrapper<>();
        userWrapper3.eq(UserDO::getShareUid, uid);
        userWrapper3.gt(UserDO::getAgencyGrade, AgencyGradeEnum.NO.getCode());
        map.put("agencyNum", count(userWrapper3));

        //vip付费金额
        List<Integer> uids = userList.stream().map(UserDO::getUid).collect(Collectors.toList());
        Integer vipMoney = 0;
        if (ObjectUtil.isNotEmpty(uids)) {
            vipMoney = walletLogMapper.calcTotal(uids, TransactionTypeEnum.RECHARGE_AMOUNT.getCode());
        }
        map.put("vipMoney", vipMoney);

        return map;
    }
}
